 local addon, ns = ...
local LabelUI = ns.LabelUI  
local cfg = ns.cfg
local profile = ns.profile
local _G = _G

local toc
 
local playerclass =  select(2, UnitClass("player"))
local playername = UnitName("player")
local classcolor = RAID_CLASS_COLORS[playerclass]
local configframe
local chatfuncs = {}
local pointsbase = {}
local timers = {}
local StyleCallBack = {}
local CallBack = {}

local procsid = {
--	[126577] = 45, -- Light of the Cosmos
--	[128985] = 50, -- Relic of Yu'lon
	[32216] = 0, -- Victory Rush
	[138279] = 0, -- Prot Warrior T15 2P
--	[138786] = "calc", -- Wushoolay's Final Choice
--	[138898] = "calc", -- Breath of the Hydra
	[137590] = "calc", -- meta, int dps
--	[138963] = "calc", -- Unerring Vision of Lei Shen
	[146046] = 115, --Purified Bindings of Immerseus
	[146184] = "calc", --Black Blood of Y'Shaarj
}

local GetTalentId = function()
    if (toc < 50000) then
        return GetActiveTalentGroup()
    else
        return GetActiveSpecGroup()
    end
end

local function ShortNumber(num)
	if not num then
		return 0
	end
	if num >= 1e6 then
		return ("%.1fm"):format(num / 1e6):gsub("%.?0+([km])$", "%1")
	elseif num >= 1e3 or num <= -1e3 then
		return ("%.1fk"):format(num / 1e3):gsub("%.?0+([km])$", "%1")
	else
		return num
	end
end

local function noshow()
   return
end
local function Kill(object, func, func2)
      if object.UnregisterAllEvents then
		object:UnregisterAllEvents()
      end
      object.Show = func or noshow
      object:Hide()
      object.Hide = func2 or noshow
end

local function CheckRaidStatus()
	local inInstance, instanceType = IsInInstance()
	if ((IsInGroup() and not IsInRaid()) or UnitIsGroupLeader('player') or UnitIsGroupAssistant("player")) and not (inInstance and (instanceType == "pvp" or instanceType == "arena")) then
		return true
	else
		return false
	end
end

local function named(name)
	return configframe.named[name]
end

local function mainframe(name)
	return configframe[name]
end

local point = function(string, self)
	local var
	if string == "self" then
		if self then
			var = self
		else
			var = UIParent
		end
	else
		_G.LabelPointGlobal = self
		local func = loadstring("local self = _G.LabelPointGlobal; return "..string)
		if type(func) == "function" then
			var = func()
		end
		_G.LabelPointGlobal = nil
		if not var then var = UIParent end	
	end
	return var
end
local function SplitTableString(var, name, ...)
	if ... then
		if not var then
			var = LabelUIcfg["SaveVars"]
		end
		if not var[name] or type(var[name]) ~= "table" then
			var[name] = {}
		end
		var = var[name]	
		return SplitTableString(var, ...)
	else
		return var, name	
	end
end

local function get(self, name, default)
	if strfind(name, "|") then
		local var, name = SplitTableString(nil, strsplit("|", name))
		if var[name] then
			return var[name]
		else
			var[name] = default
			return default	
		end		
	else
		if LabelUIcfg["SaveVars"][name] then
			return LabelUIcfg["SaveVars"][name]
		else
			LabelUIcfg["SaveVars"][name] = default
			return default	
		end
	end
end

local function set(self, name, data)
	if strfind(name, "|") then
		local var, name = SplitTableString(nil, strsplit("|", name))
		var[name] = data	
	else
		LabelUIcfg["SaveVars"][name] = data
	end
end

local function setpoint(self, id, frame, ...)
	if frame then
		if not pointsbase[id] then
			pointsbase[id] = {}
		end
		local x, y, a1, a2 = ...
		if x then
			pointsbase[id].frame = frame
			pointsbase[id].x = x
			pointsbase[id].y = y
			if a1 then
				pointsbase[id].a1 = a1
			end
			if a2 then
				pointsbase[id].a2 = a2
			end
		end
		pointsbase[id].enable = true
	elseif id then
		if pointsbase[id] then
			pointsbase[id].enable = false
		end
	end
	if LabelUI.TTPoints and LabelUI.TTPoints.Update then
		LabelUI.TTPoints:Update(pointsbase)
	end
end

local function getbase(self)
	return pointsbase
end

local function getfreetimer()
	local id = #timers
	for i = 0, id do
		if not timers[i] or not timers[i].use then
			return i
		end
	end
	return id + 1
end

local function updatetimer()
	for i, timer in pairs(timers) do
		if timers[i].use and GetTime() > timer.endtime then
			timers[i].use = false
			timer.func()
		end
	end
end

local function addtimer(self, cd, func)
	local timer = {}
	timer.endtime = cd + GetTime()
	timer.func = func
	timer.use = true
	local id = getfreetimer()
	timers[id] = timer
	return id
end

local function deltimer(self, id)
	tremove(timers, id)
end

local function CreateConfigFrame()
	if not configframe then
		configframe = CreateFrame("Frame", "LUI_ConfigFrame", UIParent)
		configframe:SetPoint("CENTER")
		configframe:SetHeight(300)
		configframe:SetWidth(400)
		local backdrop = {
			bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
			edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
			edgeSize = 25,
			insets = { left = 4, right = 4, top = 4, bottom = 4 },
		}
		configframe:SetBackdrop(backdrop)
		configframe:SetBackdropColor(0,0,0,0.5)
		configframe:EnableMouse(true)
		configframe:SetMovable(true)
		--configframe:RegisterForDrag()
		configframe:SetScript("OnMouseDown", function() configframe:StartMoving() end)
		configframe:SetScript("OnMouseUp", function() configframe:StopMovingOrSizing()  end)
		--configframe:SetUserPlaced(true)
		configframe.title = configframe:CreateFontString(nil, 'OVERLAY')
		configframe.title:SetPoint("TOPRIGHT", -15, -15)
		configframe.title:SetPoint("TOPLEFT", 15, -15)
		configframe.title:SetHeight(22)
		configframe.title:SetFont("Interface\\AddOns\\LabelUI\\media\\Aquarion.otf", 16)
		configframe.title:SetJustifyH("CENTER")
		configframe.title:SetText("LabelUI Config")
    	configframe.cancelbtn = CreateFrame("Button", nil, configframe, "UIPanelButtonTemplate")
    	configframe.cancelbtn:SetNormalFontObject("GameFontNormalSmall")
    	configframe.cancelbtn:SetHighlightFontObject("GameFontHighlightSmall")
    	configframe.cancelbtn:SetDisabledFontObject("GameFontDisableSmall")
   		configframe.cancelbtn:SetHeight(24)
    	configframe.cancelbtn:SetPoint("BOTTOMRIGHT", configframe, "BOTTOMRIGHT", -15, 15)
    	configframe.cancelbtn:SetText(CANCEL)
    	configframe.cancelbtn:SetWidth(80)
   		configframe.okbtn = CreateFrame("Button", nil, configframe, "UIPanelButtonTemplate")
    	configframe.okbtn:SetNormalFontObject("GameFontNormalSmall")
    	configframe.okbtn:SetHighlightFontObject("GameFontHighlightSmall")
    	configframe.okbtn:SetDisabledFontObject("GameFontDisableSmall")
    	configframe.okbtn:SetHeight(24)
    	configframe.okbtn:SetPoint("RIGHT", configframe.cancelbtn, "LEFT", -5, 0)
    	configframe.okbtn:SetText(OKAY)
    	configframe.okbtn:SetWidth(80) 
		configframe.frames = {}
		configframe.named = {}
		configframe:Hide()
		LabelUI.ConfigFrame = configframe
	end	
end

local function DestroyConfigFrame()
	local configframe = LabelUI.ConfigFrame
	if configframe then
		for i, v in pairs(configframe.frames) do
			v:Hide()
			v = nil
		end
		configframe.named = nil
		configframe.named = {}
		configframe.frames = nil
		configframe.frames = {}
		configframe.cancelbtn:SetScript("OnClick", noshow)
		configframe.okbtn:SetScript("OnClick", noshow)
		configframe:StopMovingOrSizing()
		configframe:Hide()
	end	
end

local dropdown_onload = function(self)
	for i, v in pairs(self.all) do
		local info            = {}
       	info.text       = v
		info.checked    = (self.curent == v)
       	info.func       = function()
			self.curent = v
			self.text:SetText(v)
			if self.func then
				self.func(self)
			end
		end
       	UIDropDownMenu_AddButton(info)
	end
end

local function CreateSimpleFrame(configframe, frametype, typename, template, name)
	local frame
	if not name then
		name = "unnamed"
	end
	if not _G["LUI_Config_"..typename.."_"..name] then 
		frame = CreateFrame(frametype, "LUI_Config_"..typename.."_"..name, configframe, template)
	else
		if not _G["LUI_Config_"..typename.."_"..name]:IsShown() then
			frame = _G["LUI_Config_"..typename.."_"..name]
			frame:Show()
		elseif name == "unnamed" then
			local index = 2
			while not frame do
				local locname = name..index
				if not _G["LUI_Config_"..typename.."_"..locname] then 
					frame = CreateFrame(frametype, "LUI_Config_"..typename.."_"..locname, configframe, template)
					frame:Show()
				elseif not _G["LUI_Config_"..typename.."_"..locname]:IsShown() then
					frame = _G["LUI_Config_"..typename.."_"..locname]
					frame:Show()
				else
					index = index + 1
				end
			end
		else
			return
		end
	end
	return frame
end

local function CreateConfigUIElement(element, configframe)
	local frame
	if element.type == "label" then
		frame = configframe:CreateFontString(nil, 'OVERLAY')
		frame.type = "label"
		if element.point then
			frame:SetPoint(element.point.a1, point(element.point.af, configframe), element.point.a2, element.point.x, element.point.y)
		end
		if element.point2 then
			frame:SetPoint(element.point2.a1, point(element.point2.af, configframe), element.point2.a2, element.point2.x, element.point2.y)
		end
		if element.height then
			frame:SetHeight(element.height)
		end
		if element.width then
			frame:SetWidth(element.width)
		end
		frame:SetFont(element.font or "Interface\\AddOns\\LabelUI\\media\\Aquarion.otf", element.size or 14)
		frame:SetJustifyH(element.justifyh or "CENTER")
		frame:SetText(element.text)
		frame.Disable = function()
			frame:SetAlpha(0.3)
		end
		frame.Enable = function()
			frame:SetAlpha(1)
		end
		if element.disable then
			frame:Disable()
		end
		if element.name then
			configframe.named[element.name] = frame
		end
	elseif element.type == "dropdown" then
		frame = CreateSimpleFrame(configframe, "Frame", "DropDown", "UIDropDownMenuTemplate", element.name)
		frame.type = "dropdown"
		if element.point then
			frame:SetPoint(element.point.a1, point(element.point.af, configframe), element.point.a2, element.point.x, element.point.y)
		end
		if element.point2 then
			frame:SetPoint(element.point2.a1, point(element.point2.af, configframe), element.point2.a2, element.point2.x, element.point2.y)
		end
		if element.height then
			frame:SetHeight(element.height)
		end
		if element.width then
			frame:SetWidth(element.width)
		end
		frame.all = element.all
		frame.curent = element.curent
		UIDropDownMenu_Initialize(frame, dropdown_onload)
		if not frame.text then
			frame.text = frame:CreateFontString(nil, 'OVERLAY')
		end
		frame.text:SetPoint("LEFT", frame, "LEFT", 25, 2)
		frame.text:SetPoint("RIGHT", frame, "RIGHT", -45, 2)
		frame.text:SetFont(element.font or "Interface\\AddOns\\LabelUI\\media\\Aquarion.otf", element.size or 14)
		frame.text:SetText(frame.curent)
		frame.text:SetJustifyH("LEFT")
		if element.func then
			frame.func = element.func
		else
			frame.func = nil
		end
		if element.name then
			configframe.named[element.name] = frame
		end
	elseif element.type== "button" then
		frame = CreateFrame("Button", nil, configframe, "UIPanelButtonTemplate")
		frame.type = "button"
		frame:SetNormalFontObject("GameFontNormalSmall")
		frame:SetHighlightFontObject("GameFontHighlightSmall")
		frame:SetDisabledFontObject("GameFontDisableSmall")
		if element.point then
			frame:SetPoint(element.point.a1, point(element.point.af, configframe), element.point.a2, element.point.x, element.point.y)
		end
		if element.point2 then
			frame:SetPoint(element.point2.a1, point(element.point2.af, configframe), element.point2.a2, element.point2.x, element.point2.y)
		end
		if element.height then
			frame:SetHeight(element.height)
		end
		frame:SetText(element.text)
		if element.width then
			frame:SetWidth(element.width)
		else
			frame:SetWidth(frame:GetTextWidth() + 20) 
		end
		frame:SetScript("OnClick", element.func) 
		if element.name then
			configframe.named[element.name] = frame
		end
	elseif element.type== "checkbox" then
		frame = CreateSimpleFrame(configframe, "CheckButton", "CheckBox", "ChatConfigCheckButtonTemplate", element.name)
		frame.type = "checkbox"
		frame:EnableMouse(true)
		if element.point then
			frame:SetPoint(element.point.a1, point(element.point.af, configframe), element.point.a2, element.point.x, element.point.y)
		end
		if element.point2 then
			frame:SetPoint(element.point2.a1, point(element.point2.af, configframe), element.point2.a2, element.point2.x, element.point2.y)
		end
		if element.height then
			frame:SetHeight(element.height)
		end
		if element.width then
			frame:SetWidth(element.width)
		end
		if element.checked then
			frame:SetChecked(true)
		else
			frame:SetChecked(false)
		end
		if element.text then
			_G[frame:GetName()..'Text']:SetText(element.text)
			--frame:SetText(element.text)
			_G[frame:GetName()..'Text']:SetFont(element.font or "Interface\\AddOns\\LabelUI\\media\\Aquarion.otf", element.size or 14)
			_G[frame:GetName()..'Text']:SetJustifyH(element.justifyh or "CENTER")
		else
			_G[frame:GetName()..'Text']:SetText("")
		end
		if element.func then
			frame:SetScript("OnClick", element.func)
		end
		if not frame.trueDisable then
			frame.trueDisable = frame.Disable
			frame.Disable = function()
				frame:trueDisable()
				_G[frame:GetName()..'Text']:SetAlpha(0.3)
			end
		end
		if not frame.trueEnable then
			frame.trueEnable = frame.Enable
			frame.Enable = function()
				frame:trueEnable()
				_G[frame:GetName()..'Text']:SetAlpha(1)
			end
		end
		if element.disable then
			frame:Disable()
		end
		if element.name then
			configframe.named[element.name] = frame
		end
	end
    return frame	
end

local function InitConfigFrame(elementtable, height, width, okfunck, cancelfunc)
	CreateConfigFrame()
	local configframe = LabelUI.ConfigFrame
	local index = 1
	if configframe:IsShown() then
		DestroyConfigFrame()
	end
	configframe:SetHeight(height or 300)
	configframe:SetWidth(width or 400)
	--for i,element in pairs(elementtable) do
	for i = 1, #(elementtable) do
		local element = elementtable[i]
		if type(element) == "table" then
			local frame = CreateConfigUIElement(element, configframe)
			if frame then
				configframe.frames[index] = frame
				index = index + 1
			end
		end	
	end
	if okfunck then
		configframe.okbtn:SetScript("OnClick", function()
			okfunck(configframe)
			DestroyConfigFrame()
		end)
		configframe.okbtn:Show()
	else
		configframe.okbtn:Hide()
	end
	if cancelfunc then
		configframe.cancelbtn:SetScript("OnClick", function()
			cancelfunc(configframe)
			DestroyConfigFrame()
		end)
	else
		configframe.cancelbtn:SetScript("OnClick", function()
			DestroyConfigFrame()
		end)
	end
	for i,v in pairs(StyleCallBack) do
		v(configframe)
	end
	configframe:Show()
end

local function ProfileChanger(curent, all, configvar)
	if not StaticPopupDialogs["LabelUIMakeReloadUI"] then
		StaticPopupDialogs["LabelUIMakeReloadUI"] = {
			text = "For enable config you need to reload UI, do it now?",
			button1 = YES,
			button2 = NO,
			sound = "levelup2",
			whileDead = 1,
			hideOnEscape = 1,
			timeout = 0,
			OnAccept = function()
				ReloadUI()
			end,
		}
	end
	local elementtable = {
		[1] = {
			type = "label",
			point = { a1 = "TOPRIGHT", a2 = "BOTTOMRIGHT", af = "self.title", x = 0, y = 0 }, 
			point2 = { a1 = "TOPLEFT", a2 = "BOTTOMLEFT", af = "self.title", x = 0, y = 0 }, 	
			height = 60,
			font = "Interface\\AddOns\\LabelUI\\media\\Aquarion.otf",
			size = 14,
			justifyh = "CENTER",
			text = "Curent profile is \""..curent.."\". Save this or select another and save it.",
			name = "mainlabel",
		},
		[2] = {
			type = "dropdown",
			point = { a1 = "TOPLEFT", a2 = "BOTTOM", af = "self.named['mainlabel']", x = -80, y = 0 }, 
			point2 = { a1 = "RIGHT", a2 = "BOTTOM", af = "self.named['mainlabel']", x = 80, y = 0 }, 	
			all = all,
			curent = curent,
			font = "Interface\\AddOns\\LabelUI\\media\\Aquarion.otf",
			size = 13,
			name = "maindropdown",
		},
	}
	local func = function(self)
		configvar["profile"] = self.named['maindropdown'].text:GetText()
	  	if self.named['maindropdown'].text:GetText() ~= curent then
	  	 	StaticPopup_Show("LabelUIMakeReloadUI")
      	end	
	end
	InitConfigFrame(elementtable, 250, 250, func)
end

local function chatmsg(msg, editbox)
	local args = {}
	if strfind(msg, " ") then
		local count = 0
		while strfind(msg, "  ") and count < 1024 do
			local pos1, pos2 = strfind(msg, "  ")
			msg = strsub(msg, 1, pos1)..strsub(msg, pos2 + 1, -1)
			count = count + 1
		end
		args = { strsplit(" ", msg) }
	else
		args[1] = msg
	end
	if #(chatfuncs.names) > 0 then
		if chatfuncs.funcs[strlower(args[1])] then
			local func = chatfuncs.funcs[args[1]]
			func(args)
		else
			local elementtable = {}
			local index = 1
			for i,v in pairs(chatfuncs.names) do
				elementtable[index] = {
					type = "button",
					point = { a1 = "TOP", a2 = "BOTTOM", af = "self.title", x = 0, y = -5 }, 	
					height = 25,
					width = 80,
					text = v,
					name = "button"..index,
					func = function() 
						DestroyConfigFrame()
						chatfuncs.funcs[strlower(v)]()
					end,
				}
				if index > 1 then
					elementtable[index].point.af = "self.named['button"..(index - 1).."']"
				end
				index = index +1
			end
			local height = 250
			if index > 5 then
				height = height + 30*(index - 5)
			end
			InitConfigFrame(elementtable, height, 250)
		end
	else
		print("|cff19ccb1LabelUI:|r Loaded")
	end
end

local function AddChatFunc(name, func)
	if not chatfuncs.names then
		chatfuncs.names = {}
	end
	if not chatfuncs.funcs then
		chatfuncs.funcs = {}
	end	
	local index = #(chatfuncs.names) + 1
	chatfuncs.funcs[strlower(name)] = func
	chatfuncs.names[index] = name
end

local function ReturnChatFunc()
	return chatfuncs.names, chatfuncs.funcs
end

local InitConfig = function()
	LabelUI.SaveVars = {}
	LabelUI.SaveVars.Get = get
	LabelUI.SaveVars.Set = set
	LabelUI.TTPoints = {}
	LabelUI.TTPoints.Base = getbase
	LabelUI.TTPoints.Set = setpoint
	LabelUI.Timer = CreateFrame("Frame", "LUI_Timer", UIParent)
	LabelUI.Timer:SetScript("OnUpdate", updatetimer)
	LabelUI.Timer:Show()
	LabelUI.Timer.Start = addtimer
	LabelUI.Timer.Stop = deltimer
	SLASH_LABELUI1 = '/LabelUI'
	SlashCmdList.LABELUI = chatmsg
	local cprof = function(args)
		if args and args[2] and profile[args[2]] then
			if not StaticPopupDialogs["LabelUIMakeReloadUI"] then
				StaticPopupDialogs["LabelUIMakeReloadUI"] = {
					text = "For enable config you need to reload UI, do it now?",
					button1 = YES,
					button2 = NO,
					sound = "levelup2",
					whileDead = 1,
					hideOnEscape = 1,
					timeout = 0,
					OnAccept = function()
						ReloadUI()
					end,
				}
			end	
			local cur = LabelUIcfg["profile"]	
			LabelUIcfg["profile"] = args[2]
	  		if args[2] ~= cur then
	  	 		StaticPopup_Show("LabelUIMakeReloadUI")
      		end	
		else
			local all = {}
			local cur
			if LabelUIcfg["profile"] and profile[LabelUIcfg["profile"]] then
				cur = LabelUIcfg["profile"]
			end
			for i,v in pairs(profile) do
				if type(i) == "string" then
					if not cur then
						cur = i
					end
					tinsert(all, i)
				end
			end
			ProfileChanger(cur, all, LabelUIcfg)
		end
	end
	AddChatFunc("Profile", cprof)
   
	local bgfile, edgefile = "", ""  
  	if cfg.color.classcolored then
    		cfg.color.normal = classcolor
  	end
  	if cfg.background.showshadow then edgefile = cfg.textures.outer_shadow end  
  	if cfg.background.useflatbackground and cfg.background.showbg then bgfile = cfg.textures.buttonbackflat end
	cfg.backdrop = { 
    	bgFile = bgfile, 
    	edgeFile = edgefile,
    	tile = false,
    	tileSize = 32, 
    	edgeSize = cfg.background.inset, 
    	insets = { 
      		left = cfg.background.inset, 
      		right = cfg.background.inset, 
      		top = cfg.background.inset, 
      		bottom = cfg.background.inset,
    	},
	} 
	cfg.textureBackground = {
		bgFile = cfg.textures.defaultbg,
		edgeFile = cfg.textures.defaultbg,
		edgeSize = 1,
	}
	cfg.texturehilite = {
		bgFile = "Interface\\AddOns\\LabelUI\\media\\SolidBorder",
		edgeFile = "Interface\\AddOns\\LabelUI\\media\\SolidBorder",
		edgeSize = 1,
	}
	cfg.texturehilite2 = {
		bgFile = "Interface\\AddOns\\LabelUI\\media\\SolidBorder",
		edgeFile = "Interface\\AddOns\\LabelUI\\media\\SolidBorder",
		edgeSize = 1.5,
	}
	cfg.textureBackground2 = {
		bgFile = cfg.textures.defaultbg,
		edgeFile = "Interface\\AddOns\\LabelUI\\media\\SolidBorder",
		edgeSize = 1,
	}
	cfg.textureBackground3 = {
		bgFile = cfg.textures.defaultbg,
		edgeFile = "Interface\\AddOns\\LabelUI\\media\\SolidBorder",
		edgeSize = 2,
	}
	cfg.statusbar = cfg.textures.statusbar
	cfg.buffborder = "Interface\\AddOns\\LabelUI\\media\\buffborder.tga"
	cfg.textureBackground3 = {
		bgFile = cfg.textures.defaultbg,
		insets = {top = -1.5, left = -1.5, bottom = -1.5, right = -1.5},
		}
	cfg.textureBar = {
		bgFile = cfg.textures.statusbar,
		insets = {top = 0, left = 0, bottom = 0, right = 0},
	} 	
end

function LabelUI.AddInit(self, func, name)
	tinsert(LabelUI.Init, {func = func, name = name})
end
   
_,_,_,toc = GetBuildInfo()
LabelUI.toc = toc
LabelUI.CheckRaidStatus = CheckRaidStatus
LabelUI.ShortNumber = ShortNumber
LabelUI.CallBack = CallBack
LabelUI.point = point
LabelUI.noshow = noshow
LabelUI.Kill = Kill 
LabelUI.InitConfig = InitConfig
LabelUI.InitConfigFrame = InitConfigFrame
LabelUI.ProfileChanger = ProfileChanger
LabelUI.AddChatFunc = AddChatFunc
LabelUI.ReturnChatFunc = ReturnChatFunc
LabelUI.DestroyConfigFrame = DestroyConfigFram
LabelUI.StyleCallBack = StyleCallBack
LabelUI.GetTalentId = GetTalentId
cfg.classcolor = classcolor 
cfg.playerclass = playerclass
cfg.playername = playername
cfg.procsid = procsid